package com.xukun.changgou.gateway.filter;

import com.alibaba.fastjson.JSON;
import com.xukun.changgou.common.constants.CommonConstant;
import com.xukun.changgou.common.redis.RedisUtil;
import com.xukun.changgou.common.response.ResponseData;
import com.xukun.changgou.common.response.ResponseEnum;
import com.xukun.changgou.common.response.exception.BaseException;
import com.xukun.changgou.common.utils.JwtUtil;
import com.xukun.changgou.gateway.feign.sys.SysUserFeign;
import com.xukun.changgou.gateway.utils.ServerHttpUtil;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @Author xukun
 * @Date 2021-06-04 10:22
 * @Description 自定义全局网关过滤器，主要作用：1、请求转发的token验证 2、权限数据的获取传递
 */
@Component
public class BaseGlobalFilter implements GlobalFilter, Ordered {

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private SysUserFeign userFeign;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        //如果是登录请求、swagger文档相关请求就放行
        String path = request.getPath().value();
        if (StringUtils.indexOf(path, "/auth/login") != -1 || StringUtils.indexOf(path, "/swagger-resources") != -1 || StringUtils.indexOf(path, "/v2/api-docs") != -1) {
            return chain.filter(exchange);
        }

        //禁止访问内部接口
        if (StringUtils.indexOf(path, "/inner") != -1) {
            return ServerHttpUtil.doReturn(response, false, ResponseEnum.DENY_ACCESS_INNER);
        }

        //从请求头获取token
        List<String> tokenList = request.getHeaders().get(CommonConstant.TOKEN_HEADER);
        if (ObjectUtils.isEmpty(tokenList)) {
            return ServerHttpUtil.doReturn(response, false, ResponseEnum.NOT_LOGIN);
        }

        //校验token的有效性及合法性
        String subject;
        try {
            subject = checkToken(tokenList.get(0));
        } catch (BaseException e) {
            return ServerHttpUtil.doReturn(response, e);
        }

        String[] split = subject.split("\\|");
        //获取权限列表
        List<String> authorities = getAuthorities(Integer.valueOf(split[0]), split[1]);

        //将获取的权限数据放在请求头传递,同时只有获取到该值才能访问该服务的接口，保证了各微服务的安全
        String auth = JSON.toJSONString(authorities);
        ServerHttpRequest serverHttpRequest = request.mutate().header(CommonConstant.AUTH_HEADER, auth).build();
        ServerWebExchange serverWebExchange = exchange.mutate().request(serverHttpRequest).response(exchange.getResponse()).principal(exchange.getPrincipal()).build();
        return chain.filter(serverWebExchange);
    }

    @Override
    public int getOrder() {
        return 0;
    }

    /**
     * 检验token
     *
     * @param token
     * @return 返回token的主体subject
     */
    private String checkToken(String token) {
        if (ObjectUtils.isEmpty(token)) {
            throw new BaseException(ResponseEnum.INVALID_TOKEN);
        }
        //判断token是否在redis黑名单中
        if (redisUtil.hasKey(CommonConstant.REDIS_TOKEN_BLACK_LIST)) {
            Long len = redisUtil.lLen(CommonConstant.REDIS_TOKEN_BLACK_LIST);
            for (int i = 0; i < len; i++) {
                if (token.equals(redisUtil.lIndex(CommonConstant.REDIS_TOKEN_BLACK_LIST, i).split("\\|")[0])) {
                    throw new BaseException(ResponseEnum.INVALID_TOKEN);
                }
            }
        }
        //获取token中的主体并判断有效性
        String subject = "";
        try {
            subject = JwtUtil.getSubject(token);
        } catch (BaseException e) {
            throw e;
        }
        return subject;
    }

    /**
     * 获取权限列表
     *
     * @param userId   用户id
     * @param username 用户名
     * @return list 权限列表
     */
    private List<String> getAuthorities(Integer userId, String username) {
        //根据用户名取出redis中的权限数据
        List<String> authorities;
        if (redisUtil.hasKey(username + CommonConstant.REDIS_USER_AUTH_SUFFIX)) {
            //从redis中取出该username的权限数据
            String auth = redisUtil.get(username + CommonConstant.REDIS_USER_AUTH_SUFFIX);
            if (ObjectUtils.isNotEmpty(auth)) {
                authorities = JSON.parseArray(auth, String.class);
            } else {
                ResponseData<List<String>> responseData = userFeign.queryPermissionListByUser(userId);
                authorities = responseData.getData();
            }
        } else {
            ResponseData<List<String>> responseData = userFeign.queryPermissionListByUser(userId);
            authorities = responseData.getData();
        }
        return authorities;
    }
}
